#pragma once
#include <string>
#include <array>
#include <vector>
#include <map>
#include <simple_enum.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/array.hpp>
#include <cereal/types/map.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/json.hpp>










enum class PoseQuality: int8_t
{
    Good = 1,
    Bad = 2,
};


namespace simple_enum
{
namespace enum_details
{
        template <>
        inline constexpr auto names_v<PoseQuality> = std::array<std::string_view, 2>{
            "Good",
            "Bad",
        };

        template <>
        inline constexpr auto values_v<PoseQuality> = std::array<int8_t, 2>{
            1,
            2,
        };

        template <>
        inline constexpr auto entries_v<PoseQuality> = std::array<std::pair<std::string_view, int8_t>, 2>{
            std::pair<std::string_view, int8_t>("Good", 1),
            std::pair<std::string_view, int8_t>("Bad", 2),
        };
} // namespace enum_details
} // namespace simple_enum

namespace cereal {
template <class Archive> inline
std::string save_minimal( Archive const &, PoseQuality const & t )
{
    std::string str(simple_enum::enum_name<PoseQuality>(t));
    return str;
}

template <class Archive> inline
void load_minimal( Archive const &, PoseQuality & t, std::string const & value )
{
    std::string_view sv(value);
    t = simple_enum::enum_cast<PoseQuality>(sv).value();
}
} // namespace cereal


struct Vec3f
{
    float x{};
    float y{};
    float z{};
};


template<class Archive>
void serialize(Archive& archive,
               Vec3f& m) {
    archive(cereal::make_nvp("x", m.x));
    archive(cereal::make_nvp("y", m.y));
    archive(cereal::make_nvp("z", m.z));
}


struct Quat4f
{
    float x{};
    float y{};
    float z{};
    float w{};
};


template<class Archive>
void serialize(Archive& archive,
               Quat4f& m) {
    archive(cereal::make_nvp("x", m.x));
    archive(cereal::make_nvp("y", m.y));
    archive(cereal::make_nvp("z", m.z));
    archive(cereal::make_nvp("w", m.w));
}


struct Pose3f
{
    Vec3f position{};
    Quat4f orientation{};
    PoseQuality quality{};
};


template<class Archive>
void serialize(Archive& archive,
               Pose3f& m) {
    archive(cereal::make_nvp("position", m.position));
    archive(cereal::make_nvp("orientation", m.orientation));
    archive(cereal::make_nvp("quality", m.quality));
}


struct ComplexStruct
{
    std::vector<std::map<int, std::string>> foo{};
    std::map<int, std::map<int, std::vector<std::map<int, std::string>>>> bar{};
};


template<class Archive>
void serialize(Archive& archive,
               ComplexStruct& m) {
    archive(cereal::make_nvp("foo", m.foo));
    archive(cereal::make_nvp("bar", m.bar));
}



